package ch.subgate.spritestudio.widgets;

import java.util.ArrayList;
import ch.subgate.spritestudio.tools.OnAlphaChangedListener;
import ch.subgate.spritestudio.tools.OnHueChangedListener;
import ch.subgate.spritestudio.tools.OnSaturationChangedListener;
import ch.subgate.spritestudio.tools.OnValueChangedListener;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class APickerView extends View implements
OnHueChangedListener,
OnSaturationChangedListener,
OnValueChangedListener {
	
	private float mWidth;
	private float mHeight;
	
	/** Current Color in HSV Format */
	private float[] mHSVColor;
	
	/** Current alpha value */
	private int mAlpha;
	
	/** Select x coordinate */
	private float mSelectX;
	
	/** Alpha component listener */
	private ArrayList<OnAlphaChangedListener> mAlphaListeners;
	
	private Paint mShaderPaint;
	
	/** Background pattern paint */
	private Paint mPatternPaint;
	
	public APickerView(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		mWidth = 0.0f;
		mHeight = 0.0f;
		
		//Initialize the current HSV color
		mHSVColor = new float[3];
		mHSVColor[0] = 1.0f;
		mHSVColor[1] = 1.0f;
		mHSVColor[2] = 1.0f;
		
		//Initialize the current alpha value
		mAlpha = 255;
		
		//Initialize select x coordinate
		mSelectX = 0.0f;
		
		//Initialize the list of alpha listeners
		mAlphaListeners = new ArrayList<OnAlphaChangedListener>();
		
		mShaderPaint = new Paint();
		
		//Initialize the paint for the background pattern
		mPatternPaint = new Paint();
	}
	
	/** Method is invoked when the surface needs to redraw */
	@Override
	public void onDraw(Canvas canvas) {
		//Draw background pattern
		for (int i = 0; i * 36 < mWidth; i++) {
			for (int j = 0; j * 36 < mHeight; j++) {
				if ((i + j) % 2 == 0) {
					mPatternPaint.setColor(0xffaaaaaa);
					canvas.drawRect(
							(float)(i * 36),
							(float)(j * 36),
							(float)((i + 1) * 36),
							(float)((j + 1) * 36),
							mPatternPaint);
				}
				else {
					mPatternPaint.setColor(0xffcccccc);
					canvas.drawRect(
							(float)(i * 36),
							(float)(j * 36),
							(float)((i + 1) * 36),
							(float)((j + 1) * 36),
							mPatternPaint);
				}
			}
		}
		
		//Draw overlaying gradient
		Shader alpha = new LinearGradient(
				0.0f,
				0.0f,
				mWidth,
				0.0f,
				0x00000000,
				Color.HSVToColor(mHSVColor),
				Shader.TileMode.CLAMP);
		mShaderPaint.setShader(alpha);
		canvas.drawRect(
				0.0f,
				0.0f,
				mWidth,
				mHeight,
				mShaderPaint);
		
		//Draw the slider
		mPatternPaint.setStrokeWidth(9.0f);
		mPatternPaint.setColor(0x99000000);
		canvas.drawLine(
				mSelectX, 0.0f,
				mSelectX, mHeight,
				mPatternPaint);
		mPatternPaint.setStrokeWidth(3.0f);
		mPatternPaint.setColor(0xffffffff);
		canvas.drawLine(
				mSelectX, 0.0f,
				mSelectX, mHeight,
				mPatternPaint);
	}
	
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		mWidth = w;
		mHeight = h;
	}
	
	/** Method is invoked when the surface receives a touch event */
	@Override
	public boolean onTouchEvent(MotionEvent e) {
		float eventx;
		
		if (e.getX() > mWidth) {
			eventx = mWidth;
		}
		else if (e.getX() < 0.0f) {
			eventx = 0.0f;
		}
		else {
			eventx = e.getX();
		}
		
		switch (e.getAction() & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_DOWN:
		case MotionEvent.ACTION_MOVE:
			mSelectX = eventx;
			break;
		case MotionEvent.ACTION_UP:
			mSelectX = eventx;
			mAlpha = (int)((mSelectX / mWidth) * 255.0f);
			onAlphaChanged();
			break;
		}
		//Request the surface to redraw
		invalidate();
		return true;
	}
	
	/** Method is invoked when the hue component has changed */
	@Override
	public void onHueChanged(float hue) {
		mHSVColor[0] = hue;
		invalidate();
	}
	
	/** Method is invoked when the saturation component has changed */
	@Override
	public void onSaturationChanged(float saturation) {
		mHSVColor[1] = saturation;
		invalidate();
	}
	
	/** Method is invoked when the value component has changed */
	@Override
	public void onValueChanged(float value) {
		mHSVColor[2] = value;
		invalidate();
	}
	
	/** Method is invoked when selected alpha value changes */
	public void onAlphaChanged() {
		//Inform the listener
		if (!mAlphaListeners.isEmpty()) {
			for (OnAlphaChangedListener listener : mAlphaListeners) {
				listener.onAlphaChanged(mAlpha);
			}
		}
	}
	
	/** Setter for the alpha component */
	public void setAlpha(int alpha) {
		mAlpha = alpha;
		mSelectX = ((float)mAlpha / 255.0f) * mWidth;
		onAlphaChanged();
		
		//Request the surface to redraw
		invalidate();
	}
	
	/** Method to register a new alpha listener */
	public void registerAlphaListener(OnAlphaChangedListener listener) {
		mAlphaListeners.add(listener);
	}
}
